import { Injectable, Logger, BadRequestException } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository, DataSource } from "typeorm";
import {
  CasinoDiceBet,
  BetType,
  CurrencyType,
  BetStatus,
} from "../entities/casino-dice-bet.entity";
import { CasinoChibiBet, ChibiSide } from "../entities/casino-chibi-bet.entity";
import { CasinoRockPaperScissors } from "../entities/casino-rock-paper-scissors.entity";
import { GameType } from "../entities/index";
import { CasinoUnifiedRoundService } from "./casino-unified-round.service";
import {
  DiceBetData,
  ChibiBetData,
  RPSResponseData,
} from "../interfaces/casino.interface";
import { CharacterResourcesEntity } from "../../../entities/character-resources.entity";
import { CasinoDiceRound } from "../entities/casino-dice-round.entity";
import { getBetTypeFullName } from "../enums/bet-type-mapping.enum";
import { CasinoChibiRound } from "../entities/casino-chibi-round.entity";
import { CharacterEntity } from "../../../entities/character.entity";
import { PrivateMessageService } from "../../../services/private-message.service";

@Injectable()
export class CasinoBetService {
  private readonly logger = new Logger(CasinoBetService.name);

  constructor(
    @InjectRepository(CasinoDiceBet)
    private readonly diceBetRepository: Repository<CasinoDiceBet>,
    @InjectRepository(CasinoChibiBet)
    private readonly chibiBetRepository: Repository<CasinoChibiBet>,
    @InjectRepository(CasinoRockPaperScissors)
    private readonly rpsRepository: Repository<CasinoRockPaperScissors>,
    @InjectRepository(CharacterResourcesEntity)
    private readonly characterResourcesRepository: Repository<CharacterResourcesEntity>,
    @InjectRepository(CharacterEntity)
    private readonly characterRepository: Repository<CharacterEntity>,
    private readonly roundService: CasinoUnifiedRoundService,
    private readonly privateMessageService: PrivateMessageService,
    private dataSource: DataSource
  ) { }

  /**
   * 大小玩法下注
   * 同一个用户，每期只能有一个下注金和下注银的数据，如果再次下注，应该在之前基础上累加
   */
  async placeDiceBet(betData: DiceBetData): Promise<CasinoDiceBet> {
    const { userId, characterId, betType, betAmount, currencyType } = betData;

    try {
      // 验证下注金额（单次限制）
      this.validateDiceBetAmount(betAmount, currencyType);

      // 获取当前期数
      const currentRound = await this.roundService.getCurrentRound(
        GameType.DICE
      );
      if (!currentRound) {
        throw new BadRequestException("当前没有可下注的期数");
      }

      // 验证用户余额（这里需要调用用户服务）
      await this.validateUserBalance(characterId, betAmount, currencyType);

      // 验证每期单一类型下注金额限制
      await this.validateDiceBetPeriodLimit(
        userId,
        currentRound.id,
        betType,
        betAmount,
        currencyType
      );

      // 查找用户在当前期数是否已有相同类型和货币的下注记录
      const existingBet = await this.diceBetRepository.findOne({
        where: {
          roundId: currentRound.id,
          userId,
          betType,
          currencyType,
          status: BetStatus.BETTING, // 只查找下注中的记录
        },
      });

      // 使用事务处理下注逻辑
      return await this.dataSource.transaction(async (manager) => {
        let savedBet: CasinoDiceBet;
        let actualBetAmount = betAmount;

        if (existingBet) {
          // 如果存在下注记录，累加下注金额
          actualBetAmount = Number(existingBet.betAmount) + Number(betAmount);

          // 更新现有下注记录
          existingBet.betAmount = actualBetAmount;
          existingBet.updated_at = new Date();

          savedBet = await manager.save(CasinoDiceBet, existingBet);

          this.logger.log(
            `✅ 用户 ${userId} 大小玩法下注累加成功，${this.getBetTypeName(
              betType
            )} ${this.getCurrencyName(currencyType)}: ${existingBet.betAmount
            } + ${betAmount} = ${actualBetAmount}`
          );
        } else {
          // 如果不存在下注记录，创建新的下注记录
          const bet = this.diceBetRepository.create({
            roundId: currentRound.id,
            userId,
            characterId,
            betType,
            betAmount,
            currencyType,
            status: BetStatus.BETTING,
          });

          savedBet = await manager.save(CasinoDiceBet, bet);

          this.logger.log(
            `✅ 用户 ${userId} 大小玩法下注成功，${this.getBetTypeName(
              betType
            )} ${this.getCurrencyName(currencyType)}: ${betAmount}`
          );
        }

        // 扣除用户余额（仅扣本次新增金额）
        await this.deductUserBalance(
          manager,
          characterId,
          betAmount,
          currencyType
        );

        // 更新期数统计信息 后台执行就行了
        this.updateRoundBetTotals(currentRound.id, GameType.DICE, manager);

        // 验证下注统计是否更新成功
        const updatedRound = await manager
          .getRepository(CasinoDiceRound)
          .findOne({ where: { id: currentRound.id } });

        if (updatedRound) {
          this.logger.log(
            `🔍 下注后验证 - 期数 ${currentRound.id}: totalGold=${updatedRound.totalGold}, totalSilver=${updatedRound.totalSilver}`
          );
        } else {
          this.logger.warn(`⚠️ 下注后无法找到期数 ${currentRound.id}`);
        }

        return savedBet;
      });
    } catch (error) {
      this.logger.error(
        `❌ 大小玩法下注失败: ${error instanceof Error ? error.message : String(error)
        }`
      );
      throw error;
    }
  }

  /**
   * 赤壁玩法下注
   */
  async placeChibiBet(betData: ChibiBetData): Promise<CasinoChibiBet> {
    const { userId, characterId, side, betGold, betSilver } = betData;

    try {
      // 验证下注金额
      this.validateChibiBetAmount(betGold, betSilver);

      // 获取当前期数
      const currentRound = await this.roundService.getCurrentRound(
        GameType.CHIBI
      );
      if (!currentRound) {
        throw new BadRequestException("当前没有可下注的期数");
      }

      // 验证用户余额
      if (betGold > 0) {
        await this.validateUserBalance(characterId, betGold, CurrencyType.GOLD);
      }
      if (betSilver > 0) {
        await this.validateUserBalance(
          characterId,
          betSilver,
          CurrencyType.SILVER
        );
      }

      // 验证每期单一国家下注金额限制
      await this.validateChibiBetPeriodLimit(
        userId,
        currentRound.id,
        side,
        betGold,
        betSilver
      );

      // 使用事务执行所有操作
      return await this.dataSource.transaction(async (manager) => {
        // 在事务中创建下注记录
        const bet = manager.getRepository(CasinoChibiBet).create({
          roundId: currentRound.id,
          userId,
          characterId,
          side,
          betGold,
          betSilver,
          status: BetStatus.BETTING,
          winGold: 0,
          winSilver: 0,
        });

        // 保存下注记录
        const savedBet = await manager.save(CasinoChibiBet, bet);

        // 扣除用户余额
        if (betGold > 0) {
          await this.deductUserBalance(
            manager,
            characterId,
            betGold,
            CurrencyType.GOLD
          );
        }
        if (betSilver > 0) {
          await this.deductUserBalance(
            manager,
            characterId,
            betSilver,
            CurrencyType.SILVER
          );
        }

        // 更新期数统计 - 分别更新金币和银币下注
        if (betGold > 0) {
          await this.updateRoundStatistics(
            manager,
            currentRound.id,
            betGold,
            CurrencyType.GOLD
          );
        }
        if (betSilver > 0) {
          await this.updateRoundStatistics(
            manager,
            currentRound.id,
            betSilver,
            CurrencyType.SILVER
          );
        }

        this.logger.log(
          `✅ 用户 ${userId} 赤壁玩法下注成功，支援 ${this.getSideName(
            side
          )}，金币: ${betGold}，银币: ${betSilver}`
        );

        return savedBet;
      });
    } catch (error: any) {
      this.logger.error(`❌ 赤壁玩法下注失败:`, error?.message || error);
      throw error;
    }
  }

  /**
   * 发起猜拳挑战
   */
  /** 发起猜拳挑战 */
  async initiateChallenge(
    challengerId: number,
    challengerName: string,
    challengerValue: number,
    betAmount: number,
    currencyType: CurrencyType
  ): Promise<CasinoRockPaperScissors> {
    try {
      // 验证用户余额
      await this.validateUserBalance(challengerId, betAmount, currencyType);

      // 创建猜拳挑战
      const challenge = this.rpsRepository.create({
        challengerId,
        challengerName,
        challengerValue,
        betAmount,
        currencyType,
        status: 0, // 等待应战
        responderId: null,
        responderName: null,
        responderValue: null,
        winnerId: null,
        winAmount: 0,
      } as any);

      // 使用事务保存挑战记录并扣除用户余额
      return await this.dataSource.transaction(async (manager) => {
        const savedChallenge = (await manager.save(
          CasinoRockPaperScissors,
          challenge as any
        )) as CasinoRockPaperScissors;

        // 扣除用户余额
        await this.deductUserBalance(
          manager,
          challengerId,
          betAmount,
          currencyType
        );

        this.logger.log(
          `✅ 用户 ${challengerName} 发起猜拳挑战成功，下注: ${betAmount} ${this.getCurrencyName(
            currencyType
          )}`
        );

        return savedChallenge;
      });
    } catch (error: any) {
      this.logger.error(`❌ 发起猜拳挑战失败:`, error?.message || error);
      throw error;
    }
  }

  /**
   * 应战猜拳
   */
  /** 应战猜拳 */
  async respondToChallenge(
    responderId: number, // 应战者ID
    responseData: RPSResponseData
  ): Promise<CasinoRockPaperScissors> {
    const { challengeId, responderName, responderValue } = responseData;

    try {
      // 获取挑战记录
      const challenge = await this.rpsRepository.findOne({
        where: { id: challengeId, status: 0 }, // PENDING状态
      });

      if (!challenge) {
        throw new BadRequestException("挑战不存在或已被应战");
      }

      // 验证应战者余额（使用挑战时的币种）
      await this.validateUserBalance(
        responderId, // 应战者ID
        challenge.betAmount,
        challenge.currencyType as unknown as CurrencyType
      );

      // 更新挑战记录
      challenge.responderId = responderId;
      challenge.responderValue = responderValue;
      challenge.status = 1; // 已应战

      // 使用事务处理应战
      return await this.dataSource.transaction(async (manager) => {
        // 扣除应战者余额（使用挑战时的币种）
        await this.deductUserBalance(
          manager,
          responderId,
          challenge.betAmount,
          challenge.currencyType as unknown as CurrencyType
        );

        // 保存挑战记录
        const savedChallenge = (await manager.save(
          CasinoRockPaperScissors,
          challenge as any
        )) as CasinoRockPaperScissors;

        // 计算胜负（1: 石头, 2: 剪刀, 3: 布）
        const a = challenge.challengerValue;
        const b = challenge.responderValue as number; // 已赋值
        let winnerId: number | null = null;
        if (a !== b) {
          const challengerWin =
            (a === 1 && b === 2) ||
            (a === 2 && b === 3) ||
            (a === 3 && b === 1);
          winnerId = challengerWin
            ? challenge.challengerId
            : (challenge.responderId as number);
        }

        challenge.status = 2; // 已结算
        if (winnerId) {
          challenge.winnerId = winnerId;
          // 获胜者获得：本金 + 赢的金额 × 0.95（扣除5%手续费）
          const totalPot = challenge.betAmount * 2; // 总奖池（双方下注总额）
          const winningAmount = Math.floor(totalPot * 0.95); // 扣除5%手续费
          challenge.winAmount = winningAmount;

          // 发放奖励（使用挑战时的币种）
          await this.distributeWinnings(
            manager,
            winnerId,
            winningAmount,
            challenge.currencyType as unknown as CurrencyType
          );

          this.logger.log(
            `✅ 猜拳挑战 ${challengeId} 获胜者 ${winnerId} 获得奖励: ${winningAmount} (总奖池: ${totalPot}, 手续费: ${totalPot - winningAmount
            })`
          );
        } else {
          // 平局：不收手续费，分别退还各自的本金
          challenge.winnerId = null;
          challenge.winAmount = 0;

          // 退还发起者本金
          await this.distributeWinnings(
            manager,
            challenge.challengerId,
            challenge.betAmount,
            challenge.currencyType as unknown as CurrencyType
          );

          // 退还应战者本金
          await this.distributeWinnings(
            manager,
            challenge.responderId as number,
            challenge.betAmount,
            challenge.currencyType as unknown as CurrencyType
          );

          this.logger.log(
            `✅ 猜拳挑战 ${challengeId} 平局，退还双方本金: ${challenge.betAmount}`
          );
        }

        // 保存最终结果
        await manager.save(CasinoRockPaperScissors, challenge);

        this.logger.log(
          `✅ 猜拳挑战 ${challengeId} 结算完成，获胜者: ${winnerId ?? "平局"}`
        );

        // 发送私信通知给挑战者
        await this.sendChallengeResultNotification(
          challenge,
          winnerId,
          responderName
        );

        return savedChallenge;
      });
    } catch (error: any) {
      this.logger.error(`❌ 应战猜拳失败:`, error?.message || error);
      throw error;
    }
  }

  /**
   * 验证大小玩法下注金额
   */
  private validateDiceBetAmount(
    amount: number,
    currencyType: CurrencyType
  ): void {
    if (currencyType === CurrencyType.GOLD) {
      if (amount < 100 || amount > 100000) {
        throw new BadRequestException("金币下注范围：100-100000");
      }
    } else if (currencyType === CurrencyType.SILVER) {
      if (amount < 1000 || amount > 10000000) {
        throw new BadRequestException("银币下注范围：1000-10000000");
      }
    }
  }

  /**
   * 验证赤壁玩法下注金额
   */
  private validateChibiBetAmount(betGold: number, betSilver: number): void {
    if (betGold < 100 && betSilver < 1000) {
      throw new BadRequestException("增援物资不能少于100金或1000银两");
    }
  }

  /**
   * 验证大小玩法每期单一类型下注金额限制
   */
  private async validateDiceBetPeriodLimit(
    userId: number,
    roundId: number,
    betType: BetType,
    betAmount: number,
    currencyType: CurrencyType
  ): Promise<void> {
    // 查询用户在当前期数相同类型和货币的下注记录
    const existingBets = await this.diceBetRepository.find({
      where: {
        roundId,
        userId,
        betType, // 只查询相同下注类型
        currencyType,
        status: BetStatus.BETTING,
      },
    });

    // 计算当前期数该类型已下注的总金额
    const totalBetAmount = existingBets.reduce(
      (sum, bet) => sum + Number(bet.betAmount),
      0
    );

    // 计算本次下注后的总金额
    const newTotalAmount = totalBetAmount + betAmount;

    // 获取下注类型名称
    const betTypeName = this.getBetTypeName(betType);

    // 验证每期单一类型总金额限制
    if (currencyType === CurrencyType.GOLD) {
      if (newTotalAmount > 100000) {
        throw new BadRequestException(
          `每期${betTypeName}金币下注总额不能超过100000，当前已下注${totalBetAmount}，本次下注${betAmount}`
        );
      }
    } else if (currencyType === CurrencyType.SILVER) {
      if (newTotalAmount > 10000000) {
        throw new BadRequestException(
          `每期${betTypeName}银币下注总额不能超过10000000，当前已下注${totalBetAmount}，本次下注${betAmount}`
        );
      }
    }
  }

  /**
   * 验证赤壁玩法每期单一国家下注金额限制
   */
  private async validateChibiBetPeriodLimit(
    userId: number,
    roundId: number,
    side: ChibiSide,
    betGold: number,
    betSilver: number
  ): Promise<void> {
    // 查询用户在当前期数相同国家的下注记录
    const existingBets = await this.chibiBetRepository.find({
      where: {
        roundId,
        userId,
        side, // 只查询相同国家
        status: BetStatus.BETTING,
      },
    });

    // 计算当前期数该国家已下注的总金额
    const totalBetGold = existingBets.reduce(
      (sum, bet) => sum + Number(bet.betGold),
      0
    );
    const totalBetSilver = existingBets.reduce(
      (sum, bet) => sum + Number(bet.betSilver),
      0
    );

    // 计算本次下注后的总金额
    const newTotalGold = totalBetGold + betGold;
    const newTotalSilver = totalBetSilver + betSilver;

    // 获取国家名称
    const sideName = this.getSideName(side);

    // 验证每期单一国家总金额限制
    if (newTotalGold > 100000) {
      throw new BadRequestException(
        `每期${sideName}金币增援总额不能超过100000，当前已增援${totalBetGold}，本次增援${betGold}`
      );
    }
    if (newTotalSilver > 10000000) {
      throw new BadRequestException(
        `每期${sideName}银币增援总额不能超过10000000，当前已增援${totalBetSilver}，本次增援${betSilver}`
      );
    }
  }

  /**
   * 验证猜拳玩法下注金额
   */
  private validateRPSBetAmount(
    amount: number,
    currencyType: CurrencyType
  ): void {
    if (currencyType === CurrencyType.GOLD) {
      if (amount < 100 || amount > 100000) {
        throw new BadRequestException("金币下注范围：100-10000");
      }
    } else if (currencyType === CurrencyType.SILVER) {
      if (amount < 1000 || amount > 1000000) {
        throw new BadRequestException("银币下注范围：1000-1000000");
      }
    }
  }

  /**
   * 验证用户余额
   */
  private async validateUserBalance(
    characterId: number,
    amount: number,
    currencyType: CurrencyType
  ): Promise<void> {
    try {
      // 获取用户角色资源信息
      const userResources = await this.characterResourcesRepository.findOne({
        where: { characterId },
      });

      if (!userResources) {
        throw new BadRequestException("用户角色资源不存在");
      }

      const { gold, silver } = userResources;
      const currentBalance = currencyType === CurrencyType.GOLD ? gold : silver;
      const currencyName = this.getCurrencyName(currencyType);

      if (currentBalance < amount) {
        throw new BadRequestException(
          `余额不足，当前${currencyName}余额: ${currentBalance}，需要: ${amount}`
        );
      }

      this.logger.log(
        `✅ 用户 ${characterId} 余额验证通过，当前${currencyName}余额: ${currentBalance}，需要: ${amount}`
      );
    } catch (error: any) {
      this.logger.error(
        `❌ 用户 ${characterId} 余额验证失败:`,
        error?.message || error
      );
      throw error;
    }
  }

  /**
   * 扣除用户余额
   */
  private async deductUserBalance(
    manager: any,
    characterId: number,
    amount: number,
    currencyType: CurrencyType
  ): Promise<void> {
    try {
      const currencyName = this.getCurrencyName(currencyType);

      // 获取用户角色ID
      const userResources = await this.characterResourcesRepository.findOne({
        where: { characterId },
      });
      if (!userResources) {
        throw new BadRequestException("无法获取用户角色信息");
      }

      // 修复：直接使用事务管理器执行SQL更新
      // 确保余额扣除操作在事务中执行
      const currencyField =
        currencyType === CurrencyType.GOLD ? "gold" : "silver";

      // 使用事务管理器执行更新
      await manager
        .createQueryBuilder()
        .update("character_resources")
        .set({
          [currencyField]: () => `${currencyField} + :amount`,
          updated_at: new Date(),
        })
        .where("characterId = :characterId", { characterId })
        .setParameter("amount", -Number(amount))
        .execute();

      this.logger.log(
        `✅ 成功扣除用户 ${characterId} ${currencyName}余额: ${amount}`
      );
    } catch (error: any) {
      this.logger.error(
        `❌ 扣除用户 ${characterId} ${this.getCurrencyName(
          currencyType
        )}余额失败:`,
        error?.message || error
      );
      throw error;
    }
  }

  /**
   * 发放奖励
   */
  private async distributeWinnings(
    manager: any,
    characterId: number,
    amount: number,
    currencyType: CurrencyType
  ): Promise<void> {
    try {
      const currencyName = this.getCurrencyName(currencyType);

      // 获取用户角色ID
      const userResources = await this.characterResourcesRepository.findOne({
        where: { characterId },
      });
      if (!userResources) {
        throw new BadRequestException("无法获取用户角色信息");
      }

      // 修复：直接使用事务管理器执行SQL更新
      // 确保奖励发放操作在事务中执行
      const currencyField =
        currencyType === CurrencyType.GOLD ? "gold" : "silver";

      // 使用事务管理器执行更新
      await manager
        .createQueryBuilder()
        .update("character_resources")
        .set({
          [currencyField]: () => `${currencyField} + :amount`,
          updated_at: new Date(),
        })
        .where("characterId = :characterId", { characterId })
        .setParameter("amount", Number(amount))
        .execute();

      this.logger.log(
        `✅ 成功为用户 ${characterId} 发放 ${currencyName}奖励: ${amount}`
      );
    } catch (error: any) {
      this.logger.error(
        `❌ 为用户 ${characterId} 发放 ${this.getCurrencyName(
          currencyType
        )}奖励失败:`,
        error?.message || error
      );
      throw error;
    }
  }

  /**
   * 更新期数统计
   */
  private async updateRoundStatistics(
    manager: any,
    roundId: number,
    amount: number,
    currencyType: CurrencyType
  ): Promise<void> {
    try {
      // 获取当前下注记录，确定支援的国家
      const currentBet = await manager.getRepository(CasinoChibiBet).findOne({
        where: { roundId: roundId },
        order: { id: "DESC" },
      });

      if (!currentBet) {
        this.logger.warn(`未找到期数 ${roundId} 的下注记录`);
        return;
      }

      const side = Number(currentBet.side); // 确保转换为数字类型

      // 根据支援国家和货币类型更新对应的字段（使用数据库表中的实际字段名）
      let updateField = "";
      if (side === 1) {
        // 魏国
        updateField =
          currencyType === CurrencyType.GOLD
            ? "wei_total_gold"
            : "wei_total_silver";
      } else if (side === 2) {
        // 蜀国
        updateField =
          currencyType === CurrencyType.GOLD
            ? "shu_total_gold"
            : "shu_total_silver";
      } else if (side === 3) {
        // 吴国
        updateField =
          currencyType === CurrencyType.GOLD
            ? "wu_total_gold"
            : "wu_total_silver";
      } else {
        this.logger.warn(`无效的支援国家: ${side}`);
        return;
      }

      // 使用SQL更新语句累加下注金额
      const updateQuery = `
        UPDATE casino_chibi_rounds 
        SET ${updateField} = ${updateField} + ?, 
            updated_at = NOW() 
        WHERE id = ?
      `;

      await manager.query(updateQuery, [amount, roundId]);

      this.logger.log(
        `✅ 期数 ${roundId} ${this.getSideName(side)} ${this.getCurrencyName(
          currencyType
        )}下注统计更新: +${amount}`
      );
    } catch (error: any) {
      this.logger.error(`更新期数统计失败: ${error?.message || error}`);
      throw error;
    }
  }

  /**
   * 更新期数下注总金额
   */
  private async updateRoundBetTotals(
    roundId: number,
    gameType: GameType,
    manager: any
  ): Promise<void> {
    try {
      // 根据游戏类型只查询对应的下注记录，避免不必要的查询和字段映射问题
      let totalGold = 0;
      let totalSilver = 0;
      let totalChibiGold = 0;
      let totalChibiSilver = 0;
      let totalRPSGold = 0;
      let totalRPSSilver = 0;

      if (gameType === GameType.DICE) {
        // 只查询大小玩法下注统计
        const diceBets = await manager.getRepository(CasinoDiceBet).find({
          where: { roundId: roundId },
        });

        // 调试：记录所有金币下注记录
        const goldBets = diceBets.filter(
          (bet: CasinoDiceBet) => bet.currencyType === CurrencyType.GOLD
        );
        this.logger.log(
          `🔍 期数 ${roundId} 金币下注记录:`,
          goldBets.map((bet: CasinoDiceBet) => ({
            id: bet.id,
            betAmount: bet.betAmount,
            betAmountType: typeof bet.betAmount,
            betAmountValue: Number(bet.betAmount),
          }))
        );

        totalGold = goldBets.reduce((sum: number, bet: CasinoDiceBet) => {
          // 确保 betAmount 是数字类型
          const betAmount =
            typeof bet.betAmount === "string"
              ? parseInt(bet.betAmount, 10)
              : Number(bet.betAmount || 0);

          // 验证数值有效性
          if (isNaN(betAmount)) {
            this.logger.error(
              `❌ 无效的下注金额: ${bet.betAmount
              }, 类型: ${typeof bet.betAmount}`
            );
            return sum;
          }

          // 检查数值范围
          if (betAmount > Number.MAX_SAFE_INTEGER) {
            this.logger.warn(
              `⚠️ 下注金额过大: ${betAmount}, 使用安全值: ${Number.MAX_SAFE_INTEGER}`
            );
            return sum + Number.MAX_SAFE_INTEGER;
          }

          const newSum = sum + betAmount;
          this.logger.log(`🔢 累加计算: ${sum} + ${betAmount} = ${newSum}`);
          return newSum;
        }, 0);

        // 调试：记录所有银币下注记录
        const silverBets = diceBets.filter(
          (bet: CasinoDiceBet) => bet.currencyType === CurrencyType.SILVER
        );
        this.logger.log(
          `🔍 期数 ${roundId} 银币下注记录:`,
          silverBets.map((bet: CasinoDiceBet) => ({
            id: bet.id,
            betAmount: bet.betAmount,
            betAmountType: typeof bet.betAmount,
            betAmountValue: Number(bet.betAmount),
          }))
        );

        totalSilver = silverBets.reduce((sum: number, bet: CasinoDiceBet) => {
          // 确保 betAmount 是数字类型
          const betAmount =
            typeof bet.betAmount === "string"
              ? parseInt(bet.betAmount, 10)
              : Number(bet.betAmount || 0);

          // 验证数值有效性
          if (isNaN(betAmount)) {
            this.logger.error(
              `❌ 无效的下注金额: ${bet.betAmount
              }, 类型: ${typeof bet.betAmount}`
            );
            return sum;
          }

          // 检查数值范围
          if (betAmount > Number.MAX_SAFE_INTEGER) {
            this.logger.warn(
              `⚠️ 下注金额过大: ${betAmount}, 使用安全值: ${Number.MAX_SAFE_INTEGER}`
            );
            return sum + Number.MAX_SAFE_INTEGER;
          }

          const newSum = sum + betAmount;
          this.logger.log(`🔢 累加计算: ${sum} + ${betAmount} = ${newSum}`);
          return newSum;
        }, 0);

        this.logger.log(
          `🔄 开始更新期数 ${roundId} 大小玩法下注统计，金币: ${totalGold}，银币: ${totalSilver}`
        );

        const updateResult = await manager
          .getRepository(CasinoDiceRound)
          .createQueryBuilder()
          .update()
          .set({
            totalGold: totalGold,
            totalSilver: totalSilver,
          })
          .where("id = :roundId", { roundId })
          .execute();

        this.logger.log(
          `✅ 期数 ${roundId} 大小玩法下注统计更新结果:`,
          updateResult
        );

        // 验证更新是否成功
        const updatedRound = await manager
          .getRepository(CasinoDiceRound)
          .findOne({ where: { id: roundId } });

        if (updatedRound) {
          this.logger.log(
            `🔍 验证更新结果 - 期数 ${roundId}: totalGold=${updatedRound.totalGold}, totalSilver=${updatedRound.totalSilver}`
          );
        } else {
          this.logger.warn(`⚠️ 无法找到更新后的期数 ${roundId}`);
        }
      } else if (gameType === GameType.CHIBI) {
        // 只查询赤壁玩法下注统计
        const chibiBets = await manager.getRepository(CasinoChibiBet).find({
          where: { roundId: roundId },
        });

        // 根据下注记录中的side字段来分别统计各个国家的下注
        const weiBets = chibiBets.filter(
          (bet: CasinoChibiBet) => bet.side === 1
        ); // 魏国
        const shuBets = chibiBets.filter(
          (bet: CasinoChibiBet) => bet.side === 2
        ); // 蜀国
        const wuBets = chibiBets.filter(
          (bet: CasinoChibiBet) => bet.side === 3
        ); // 吴国

        const weiTotalGold = weiBets.reduce(
          (sum: number, bet: CasinoChibiBet) => sum + (bet.betGold || 0),
          0
        );
        const weiTotalSilver = weiBets.reduce(
          (sum: number, bet: CasinoChibiBet) => sum + (bet.betSilver || 0),
          0
        );
        const shuTotalGold = shuBets.reduce(
          (sum: number, bet: CasinoChibiBet) => sum + (bet.betGold || 0),
          0
        );
        const shuTotalSilver = shuBets.reduce(
          (sum: number, bet: CasinoChibiBet) => sum + (bet.betSilver || 0),
          0
        );
        const wuTotalGold = wuBets.reduce(
          (sum: number, bet: CasinoChibiBet) => sum + (bet.betGold || 0),
          0
        );
        const wuTotalSilver = wuBets.reduce(
          (sum: number, bet: CasinoChibiBet) => sum + (bet.betSilver || 0),
          0
        );

        await manager
          .getRepository(CasinoChibiRound)
          .createQueryBuilder()
          .update()
          .set({
            weiTotalGold: weiTotalGold,
            weiTotalSilver: weiTotalSilver,
            shuTotalGold: shuTotalGold,
            shuTotalSilver: shuTotalSilver,
            wuTotalGold: wuTotalGold,
            wuTotalSilver: wuTotalSilver,
          })
          .where("id = :roundId", { roundId })
          .execute();

        this.logger.log(
          `✅ 期数 ${roundId} 赤壁玩法下注统计更新完成，魏国: ${weiTotalGold}金/${weiTotalSilver}银，蜀国: ${shuTotalGold}金/${shuTotalSilver}银，吴国: ${wuTotalGold}金/${wuTotalSilver}银`
        );
      }

      // 记录日志
      this.logger.log(
        `✅ 更新期数 ${roundId} 下注总金额成功，游戏类型: ${gameType}`
      );

      this.logger.log(
        `✅ 更新期数 ${roundId} 下注总金额成功，大小玩法金币: ${totalGold}，银币: ${totalSilver}，赤壁玩法金币: ${totalChibiGold}，银币: ${totalChibiSilver}，猜拳玩法金币: ${totalRPSGold}，银币: ${totalRPSSilver}`
      );
    } catch (error: any) {
      this.logger.error(
        `❌ 更新期数 ${roundId} 下注总金额失败:`,
        error?.message || error
      );
    }
  }

  /**
   * 获取当前期数
   */
  private async getCurrentRound(gameType: GameType): Promise<any> {
    return await this.roundService.getCurrentRound(gameType);
  }

  /**
   * 获取货币名称
   */
  private getCurrencyName(currencyType: CurrencyType): string {
    return currencyType === CurrencyType.GOLD ? "金币" : "银币";
  }

  /**
   * 获取下注类型名称
   */
  private getBetTypeName(betType: BetType): string {
    return getBetTypeFullName(betType);
  }

  /**
   * 获取国家名称
   */
  private getSideName(side: ChibiSide): string {
    const names = {
      [ChibiSide.WEI]: "魏国",
      [ChibiSide.SHU]: "蜀国",
      [ChibiSide.WU]: "吴国",
    };
    return names[side] || "未知";
  }

  /**
   * 获取用户下注记录
   */
  async getUserBets(
    characterId: number,
    gameType: GameType,
    pageNum: number = 0,
    pageSize: number = 20
  ): Promise<{
    bets: any[];
    total: number;
    page: number;
  }> {
    try {
      let repository: Repository<any>;
      let whereCondition: any;

      switch (gameType) {
        case GameType.DICE:
          repository = this.diceBetRepository;
          whereCondition = { characterId };
          break;
        case GameType.CHIBI:
          repository = this.chibiBetRepository;
          whereCondition = { characterId };
          break;
        case GameType.ROCK_PAPER_SCISSORS:
          repository = this.rpsRepository;
          whereCondition = [
            { challengerId: characterId },
            { responderId: characterId },
          ];
          break;
        default:
          throw new BadRequestException("无效的游戏类型");
      }

      const [bets, total] = await repository.findAndCount({
        where: whereCondition,
        order: { created_at: "DESC" },
        skip: pageNum * pageSize,
        take: pageSize,
      });

      const result = {
        bets,
        total,
        page: pageNum,
      };

      return result;
    } catch (error: any) {
      this.logger.error(`❌ 获取用户下注记录失败:`, error?.message || error);
      return { bets: [], total: 0, page: pageNum };
    }
  }

  /**
   * 获取用户大小玩法下注记录（带期数信息）
   */
  async getUserDiceBetsWithRoundInfo(
    characterId: number,
    pageNum: number = 0,
    pageSize: number = 20
  ): Promise<{
    bets: any[];
    total: number;
    page: number;
  }> {
    try {
      // 直接查询下注记录，不尝试连接不存在的 round 关系
      const [bets, total] = await this.diceBetRepository
        .createQueryBuilder("bet")
        .where("bet.characterId = :characterId", { characterId })
        .orderBy("bet.created_at", "DESC")
        .skip(pageNum * pageSize)
        .take(pageSize)
        .getManyAndCount();

      // 处理查询结果，使用 roundId 作为期数标识
      const betsWithRoundInfo = bets.map((bet: any) => {
        return {
          ...bet,
          roundNumber: bet.roundId, // 直接使用 roundId 作为期数编号
        };
      });

      return {
        bets: betsWithRoundInfo,
        total,
        page: pageNum,
      };
    } catch (error: any) {
      this.logger.error(
        `❌ 获取用户大小玩法下注记录失败:`,
        error?.message || error
      );
      return { bets: [], total: 0, page: pageNum };
    }
  }

  /**
   * 获取大小玩法中奖下注记录
   */
  async getDiceWinningBets(
    roundId: number,
    pageNum: number = 0,
    pageSize: number = 20
  ): Promise<{
    bets: any[];
    total: number;
    page: number;
  }> {
    try {
      // 通过关联查询一次性获取下注记录和角色名称，只选择需要的字段
      const rawBets = await this.diceBetRepository
        .createQueryBuilder("bet")
        .leftJoin("characters", "char", "char.id = bet.characterId")
        .select([
          "bet.id as id",
          "bet.roundId as roundId",
          "bet.userId as userId",
          "bet.characterId as characterId",
          "bet.betType as betType",
          "bet.betAmount as betAmount",
          "bet.currencyType as currencyType",
          "bet.status as status",
          "bet.winAmount as winAmount",
          "bet.created_at as created_at",
          "bet.updated_at as updated_at",
          "char.name as characterName",
        ])
        .where("bet.roundId = :roundId", { roundId })
        .andWhere("bet.winAmount > 0")
        .andWhere("bet.status = :status", { status: BetStatus.SETTLED })
        .orderBy("bet.winAmount", "DESC") // 按中奖金额降序排列
        .skip(pageNum * pageSize)
        .take(pageSize)
        .getRawMany();

      // 获取总数
      const total = await this.diceBetRepository
        .createQueryBuilder("bet")
        .where("bet.roundId = :roundId", { roundId })
        .andWhere("bet.winAmount > 0")
        .andWhere("bet.status = :status", { status: BetStatus.SETTLED })
        .getCount();

      return {
        bets: rawBets,
        total,
        page: pageNum,
      };
    } catch (error: any) {
      this.logger.error(
        `❌ 获取大小玩法中奖下注记录失败:`,
        error?.message || error
      );
      return { bets: [], total: 0, page: pageNum };
    }
  }

  /**
   * 获取赤壁玩法中奖下注记录
   */
  async getChibiWinningBets(
    roundId: number,
    pageNum: number = 0,
    pageSize: number = 20
  ): Promise<{
    bets: any[];
    total: number;
    page: number;
  }> {
    try {
      // 通过关联查询一次性获取下注记录和角色名称，只选择需要的字段
      const rawBets = await this.chibiBetRepository
        .createQueryBuilder("bet")
        .leftJoin("characters", "char", "char.id = bet.characterId")
        .select([
          "bet.id as id",
          "bet.roundId as roundId",
          "bet.userId as userId",
          "bet.characterId as characterId",
          "bet.side as side",
          "bet.betGold as betGold",
          "bet.betSilver as betSilver",
          "bet.winGold as winGold",
          "bet.winSilver as winSilver",
          "bet.status as status",
          "bet.created_at as created_at",
          "bet.updated_at as updated_at",
          "char.name as characterName",
        ])
        .where("bet.roundId = :roundId", { roundId })
        .andWhere("(bet.winGold > 0 OR bet.winSilver > 0)")
        .andWhere("bet.status = :status", { status: BetStatus.SETTLED })
        .orderBy("(bet.winGold + bet.winSilver)", "DESC") // 按中奖金额降序排列
        .skip(pageNum * pageSize)
        .take(pageSize)
        .getRawMany();

      // 获取总数
      const total = await this.chibiBetRepository
        .createQueryBuilder("bet")
        .where("bet.roundId = :roundId", { roundId })
        .andWhere("(bet.winGold > 0 OR bet.winSilver > 0)")
        .andWhere("bet.status = :status", { status: BetStatus.SETTLED })
        .getCount();

      // 处理数据格式，统一为winAmount字段
      const processedBets = rawBets.map((bet) => ({
        ...bet,
        winAmount: (Number(bet.winGold) || 0) + (Number(bet.winSilver) || 0),
        currencyType: bet.winGold > 0 ? 1 : 2, // 1=金子, 2=银子
      }));

      return {
        bets: processedBets,
        total,
        page: pageNum,
      };
    } catch (error: any) {
      this.logger.error(
        `❌ 获取赤壁玩法中奖下注记录失败:`,
        error?.message || error
      );
      return { bets: [], total: 0, page: pageNum };
    }
  }

  /**
   * 获取猜拳挑战列表
   */
  async getRPSChallenges(
    pageNum: number = 0,
    pageSize: number = 20
  ): Promise<{
    challenges: CasinoRockPaperScissors[];
    total: number;
    page: number;
  }> {
    try {
      const [challenges, total] = await this.rpsRepository.findAndCount({
        where: { status: 0 }, // PENDING状态
        order: { created_at: "ASC" },
        skip: pageNum * pageSize,
        take: pageSize,
      });

      return {
        challenges,
        total,
        page: pageNum,
      };
    } catch (error: any) {
      this.logger.error(`❌ 获取猜拳挑战列表失败:`, error?.message || error);
      return { challenges: [], total: 0, page: pageNum };
    }
  }

  /**
   * 发送猜拳挑战结果私信通知给挑战者
   */
  private async sendChallengeResultNotification(
    challenge: CasinoRockPaperScissors,
    winnerId: number | null,
    responderName: string
  ): Promise<void> {
    try {
      // 获取挑战者角色信息
      const challengerCharacter = await this.characterRepository.findOne({
        where: { id: challenge.challengerId },
      });

      if (!challengerCharacter) {
        this.logger.warn(`挑战者角色不存在: ${challenge.challengerId}`);
        return;
      }

      // 构建消息内容
      let messageContent = "";
      const currencyName = challenge.currencyType === 1 ? "金币" : "银币";
      const betAmount = challenge.betAmount;

      if (winnerId === null) {
        // 平局
        messageContent = `【猜拳挑战结果】与${responderName}的猜拳挑战平局，双方各退还${betAmount}${currencyName}。`;
      } else if (winnerId === challenge.challengerId) {
        // 挑战者获胜
        const winAmount = challenge.winAmount || 0;
        messageContent = `【猜拳挑战结果】恭喜！您在与${responderName}的猜拳挑战中获胜，获得${winAmount}${currencyName}！`;
      } else {
        // 挑战者失败
        messageContent = `【猜拳挑战结果】很遗憾，您在与${responderName}的猜拳挑战中失败，失去了${betAmount}${currencyName}。`;
      }

      // 发送私信
      await this.privateMessageService.sendPrivateMessage({
        content: messageContent,
        senderCharacterId: 0, // 系统消息，发送者ID为0
        receiverCharacterId: challenge.challengerId,
        messageType: 2, // 系统消息
      });

      this.logger.log(
        `✅ 猜拳挑战结果私信发送成功: ${challenge.challengerId}`
      );
    } catch (error: any) {
      this.logger.error(
        `❌ 发送猜拳挑战结果私信失败:`,
        error?.message || error
      );
      // 不抛出错误，避免影响主要流程
    }
  }
}
